﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using GraphTools;
using GraphTools.OSM;

namespace clcSimplifier
{
    public class Worker
    {
        public static void DoWork(IDictionary<int,OSMNode> nodes, IDictionary<int,OSMWay> ways,
            out  IDictionary<int,OSMWay> newWays, out IDictionary<string,OSMRelation> newRelations)
        {
            newWays = new Dictionary<int,OSMWay>();
            //collect relations
            newRelations = GetRelations(ways.Values);

            //collect edges
            HashSet<Edge> edges = GetEdgesFromWays(nodes, ways);

            //calc intersections
            ICollection<OSMNode> intersectionNodes = GetIntersections(nodes, edges);

            //split all the old ways
            foreach (OSMWay way in ways.Values)
            {
                ICollection<OSMWay> tmpWays = way.SplitN(intersectionNodes);
                foreach (OSMWay tmpWay in tmpWays)
                {
                    newWays.Add(tmpWay.ID, tmpWay);
                }                
            }

            

            //remove duplicates
            Dictionary<int, OSMWay> filtered = new Dictionary<int, OSMWay>();
            foreach (OSMWay way in newWays.Values)
            {
                bool isContains = false;
                foreach (OSMWay way2 in filtered.Values)
                {
                    if (way.IsSamePath(way2)){
                        isContains=true;
                        break;
                    }
                }
                if (isContains==false) filtered.Add(way.ID,way);
            }

            //match newWays to filtered ways, adding to relation
            foreach (OSMWay way in newWays.Values)
            {
                foreach (OSMWay way2 in filtered.Values)
                {
                    if (way.IsSamePath(way2)){
                        OSMRelation.Member tmpMember = new OSMRelation.Member("way",way2.ID,string.Empty);
                        string relationKey;
                        if (way.Tags.TryGetValue("CLC:id",out relationKey)){
                            newRelations[relationKey].Members.Add(tmpMember);
                        }
                        break;
                    }
                }
            }


            //flush ways, keep filtered ways
            newWays = filtered;

            //clear tags of ways
            foreach (OSMWay way in newWays.Values)
            {
                way.Tags.Clear();
            }

        }

        protected static HashSet<Edge> GetEdgesFromWays(IDictionary<int, OSMNode> nodes, IDictionary<int, OSMWay> ways)
        {
            HashSet<Edge> result = new HashSet<Edge>();
            foreach (OSMWay w in ways.Values)
            {
                for (int i = 0; i < w.Nodes.Count - 1; i++)
                {
                    result.Add(new Edge(nodes[w.Nodes[i]], nodes[w.Nodes[i + 1]]));
                }
            }
            return result;
        }

        protected static ICollection<OSMNode> GetIntersections(IDictionary<int, OSMNode> nodes, ICollection<Edge> edges)
        {
            Dictionary<int, int> usageCount = new Dictionary<int, int>();
            //init
            foreach (OSMNode n in nodes.Values)
            {
                usageCount.Add(n.ID, 0);
            }
            foreach (Edge e in edges)
            {
                usageCount[(e.Node1 as OSMNode).ID]++;
                usageCount[(e.Node2 as OSMNode).ID]++;
            }

            ICollection<OSMNode> intersections = new List<OSMNode>();
            foreach (var u in usageCount)
            {
                if (u.Value>2)
                {
                    intersections.Add(nodes[u.Key]);
                }
            }
            return intersections;
        }

        protected static IDictionary<string, OSMRelation> GetRelations(ICollection<OSMWay> ways)
        {
            IDictionary<string, OSMRelation> result= new Dictionary<string,OSMRelation>();
            foreach (OSMWay way in ways)
            {
                string CLC_ID;
                if (way.Tags.TryGetValue("CLC:id", out CLC_ID))
                {
                    if (!result.ContainsKey(CLC_ID)){
                        OSMRelation tmprelation = new OSMRelation(OSMRelation.GetNextID(), 1, DateTime.Now,
                            new List<OSMRelation.Member>(0), new Dictionary<string, string>(way.Tags));
                        tmprelation.Tags.Add("type", "multipolygon");                        
                        result.Add(CLC_ID, tmprelation);
                    }
                }
            }
            return result;
        }
    }
}
